﻿using System.Collections.Generic;
using UnityEngine;
using Framework.Common;
using BridgeShips.FSM;
using Framework.FSM;
using Framework.Entity;

namespace BridgeShips {
    public class VirtualRehearseManager : Singleton<VirtualRehearseManager> {

        private float four_type = 29.6f;
        private float five_type = 37.0f;
        private float eight_type = 59.2f;
        private float nine_type = 66.6f;
        private float ten_type = 74.0f;

        private float m_riverWidth = 0.0f;
        private bool m_growDirection = true;

        public float faultTolerant = 0.0f;   //数据容错

        private string strFsmName = "VirtualRehearse";
        Vector2Int m_BestShipOrch = new Vector2Int( 100, 0 );
        private GameObject[] m_billBoardSprite = new GameObject[3];
        /// <summary>
        /// 初始化的数据
        /// </summary>
        private SortedDictionary<uint, FsmStateDataBase> VirtualRehearseDic = new SortedDictionary<uint, FsmStateDataBase>();

        // Use this for initialization
        public void Start() {
        }

        public List<IFsmState> GenFsmState() {
            List<IFsmState> listFsm = new List<IFsmState>();
            listFsm.Add(new VStartJumpGpsFirstPositionState());
            listFsm.Add( new VProbeState() );
            listFsm.Add( new VPosCorrectState() );
            listFsm.Add(new VAddressCorrectState());
            listFsm.Add(new VIdleState());
            listFsm.Add(new VLinkingState());
            listFsm.Add(new VLeaveState());

            return listFsm;
        }

        public void AutoDesiginBridge( float riverWidth ) {
            if (m_riverWidth != TransferOfAxes.Instance.GetRiverWidth()) {
                DestoryAll();
                m_riverWidth = riverWidth;
                Orchestration();
            }
            var m_BottomRightPoint = TransferOfAxes.Instance.m_BottomRightPoint;
            var m_TopLeftPoint = TransferOfAxes.Instance.m_TopRightPoint;
            var m_TopRightPoint = TransferOfAxes.Instance.m_TopRightPoint;
            for (int i = 0; i < m_billBoardSprite.Length; i++)
            {
                if (m_billBoardSprite[i]==null)
                {
                    GameObject billSprite = GameObject.Instantiate(Resources.Load("billboard")) as GameObject;
                    m_billBoardSprite[i] = billSprite;
                    
                }
                Material material = new Material(Shader.Find("Unity Shaders Book/Billboard"));

                m_billBoardSprite[i].GetComponent<SpriteRenderer>().material = material;


                if (i == 0)
                {
                    m_billBoardSprite[i].transform.position = m_BottomRightPoint.position + new Vector3(0, 8f, 0);
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().sprite = ShipsDictionary.Instance.m_BillSprites[0];
                    material.SetTextureScale("_MainTex", new Vector2(1f, 1));
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().drawMode = SpriteDrawMode.Sliced;
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().size = new Vector2(10.24f, 5.12f);
                    m_billBoardSprite[i].transform.localScale = new Vector3(0.5f, 0.5f, 1);

                }
                else if (i == 1)
                {
                    m_billBoardSprite[i].transform.position = m_TopLeftPoint.position + new Vector3(0, 8f, 0);
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().sprite = ShipsDictionary.Instance.m_BillSprites[1];
                    material.SetTextureScale("_MainTex", new Vector2(1f, 1));
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().drawMode = SpriteDrawMode.Sliced;
                    m_billBoardSprite[i].GetComponent<SpriteRenderer>().size = new Vector2(10.24f, 5.12f);
                    m_billBoardSprite[i].transform.localScale = new Vector3(0.5f, 0.5f, 1);
                }
                //else if (i == 2)
                //{
                //   // m_billBoardSprite[i].transform.position = m_TopRightPoint.position + new Vector3(0, 8f, 0);
                   
                //}
            }


        }

        private void Orchestration() {
            m_BestShipOrch = new Vector2Int( 50, 0 );
            int max_num = (int)((m_riverWidth * 0.5f) / four_type);
            for (int i = max_num; i >= 0; i--) {
                Vector2Int tempShipOrch = Vector2Int.zero;
                tempShipOrch.x = i;
                tempShipOrch.y = (int)((m_riverWidth - tempShipOrch.x * four_type) / five_type + 0.5f);
                if (tempShipOrch.x <= m_BestShipOrch.x && tempShipOrch.y >= m_BestShipOrch.y) {
                    m_BestShipOrch = tempShipOrch;
                }
            }
            //m_BestShipOrch = new Vector2Int( 0, 6 );
            //Orchestration
            for (int i = 0; i < m_BestShipOrch.x; i++) {
                FsmStateDataBase vd = new FsmStateDataBase();
                vd.type = (int)(ShipProperty.ShipsType.ship_Four);
                vd.length = four_type;
                vd.index = (uint)(i + 1);

                GenVData( vd.index, vd );
            }

            for (int j = 0; j < m_BestShipOrch.y; j++) {
                FsmStateDataBase vd = new FsmStateDataBase();
                vd.type = (int)(ShipProperty.ShipsType.ship_Five);
                vd.length = five_type;
                vd.index = (uint)(j + 1);

                GenVData( vd.index, vd );
            }

            ContructBridge( m_growDirection );
            ShowAll();
        }

        public void GenVData( uint id, FsmStateDataBase vd ) {
            if (!VirtualRehearseDic.ContainsKey( id )) {
                if (vd.virtualObj == null) {
                    int indexType = GameFunc.Instance.m_ShipTypes == ShipTypes.StraddleType ? 0 : 5;
                    string strName = GetResNameByType( vd.type + indexType);
                    vd.virtualObj = GameObject.Instantiate( Resources.Load( "Prefabs/Ships/" + strName ) ) as GameObject;
                    vd.virtualObj.name = "VirtualShip_" + id.ToString();
                    vd.virtualObj.GetComponentInChildren<MeshRenderer>().enabled = true;
                    
                    vd.vShipID = GetShipIDByIndex( vd.index );
                    vd.vlinkingTargetIndex = 0;
                }
                GameEntry.Instance.FsmManager.CreateFsm( vd.virtualObj, vd.virtualObj.name, GenFsmState() );
                VirtualRehearseDic.Add( id, vd );
            }
            else {
                VirtualShow( id, true );
            }
        }

        public void SwapModel( uint id, int type ) {
            GameObject tempObj = VirtualRehearseDic[id].virtualObj;
            GameObject.DestroyImmediate( tempObj );
            string strName = GetResNameByType( type );
            VirtualRehearseDic[id].virtualObj = GameObject.Instantiate( Resources.Load( "Prefabs/Ships/" + strName ) ) as GameObject;
            VirtualRehearseDic[id].virtualObj.name = "VirtualShip_" + id.ToString();
            VirtualRehearseDic[id].virtualObj.GetComponentInChildren<MeshRenderer>().enabled = true;
            VirtualRehearseDic[id].type = type;
            VirtualRehearseDic[id].length = GetLength( type );

            ContructBridge( m_growDirection );
        }

        public void SwapModelAndSort( uint[] arrID, int type ) {
            Quaternion quatCenter = Quaternion.identity;
            Vector3 vecPosition = Vector3.zero;
            foreach (var vid in arrID) {
                uint index = ShipsDictionary.Instance.HashCodeConvert( vid );
                GameObject tempObj = VirtualRehearseDic[index].virtualObj;
                vecPosition += tempObj.transform.position;
                quatCenter= tempObj.transform.localRotation;
                GameEntry.Instance.FsmManager.DestroyFsm( tempObj.name );

                GameObject.DestroyImmediate( tempObj );
            }
            vecPosition = vecPosition * 0.5f; vecPosition.y = 7.0f;
            uint id = ShipsDictionary.Instance.HashCodeConvert( arrID[0] );
            string strName = GetResNameByType( type );
            VirtualRehearseDic[id].virtualObj = GameObject.Instantiate( Resources.Load( "Prefabs/Ships/" + strName ) ) as GameObject;
            VirtualRehearseDic[id].virtualObj.name = "VirtualShip_" + id.ToString();
            VirtualRehearseDic[id].virtualObj.GetComponentInChildren<MeshRenderer>().enabled = true;
            VirtualRehearseDic[id].type = type;
            VirtualRehearseDic[id].length = GetLength( type );
            VirtualRehearseDic[id].virtualObj.transform.SetPositionAndRotation( vecPosition , quatCenter );

            GameEntry.Instance.FsmManager.CreateFsm( VirtualRehearseDic[id].virtualObj, VirtualRehearseDic[id].virtualObj.name, GenFsmState() );
            // VirtualRehearseDic.Add( id, vd );
            //sort VirtualRehearseDic
            SortVirtualRehearseDic( (int)(id + 1) );
            ContructBridge( m_growDirection );
        }

        private void SortVirtualRehearseDic( int index ) {
            VirtualRehearseDic.Remove( (uint)index );
            SortedDictionary<uint, FsmStateDataBase> tempVRDic = new SortedDictionary<uint, FsmStateDataBase>(  );
            uint locate = 0;
            foreach (var v in VirtualRehearseDic) {
                if (v.Value == null)
                    continue;
                FsmStateDataBase fsdb = new FsmStateDataBase();
                fsdb.Copy( v.Value );
                tempVRDic.Add( locate, fsdb );
                locate++;
            }
            //KeyValuePair<uint, FsmStateDataBase>[] arrFSDB = new KeyValuePair<uint, FsmStateDataBase>[VirtualRehearseDic.Count];
            //VirtualRehearseDic.CopyTo( arrFSDB ,0);
            DestoryAll();
            locate = 0;
            foreach (var v in tempVRDic) {
                VirtualRehearseDic.Add( locate, v.Value);
                locate++;
            }
        }


        public uint GetShipIDByIndex( uint id ) {
            int index = (int)id;
            index = Mathf.Clamp( index, 1, 15 );
            uint shipID = (uint)((index - 1) * 2 + 1);
            //  uint hashShipID = 
            // bool valid = ShipsDictionary.Instance.shipDic.ContainsKey( hashShipID );
            return ShipsDictionary.Instance.HashCode( shipID, shipID + 1 );
        }


        private string GetResNameByType( int type ) {
            string strName = "BriShip_Outline_4";
            switch ((ShipProperty.ShipsType)type) {
                case ShipProperty.ShipsType.ship_Four:
                    strName = "BriShip_Outline_4";
                    break;
                case ShipProperty.ShipsType.ship_Five:
                    strName = "BriShip_Outline_5";
                    break;
                case ShipProperty.ShipsType.ship_Eight:
                    strName = "BriShip_Outline_8";
                    break;
                case ShipProperty.ShipsType.ship_Nine:
                    strName = "BriShip_Outline_9";
                    break;
                case ShipProperty.ShipsType.ship_Ten:
                    strName = "BriShip_Outline_10";
                    break;
                case ShipProperty.ShipsType.line_ship_Four:
                    strName = "LineBriShip_Outline_4";
                    break;
                case ShipProperty.ShipsType.line_ship_Five:
                    strName = "LineBriShip_Outline_5";
                    break;
                case ShipProperty.ShipsType.line_ship_Eight:
                    strName = "LineBriShip_Outline_8";
                    break;
                case ShipProperty.ShipsType.line_ship_Nine:
                    strName = "LineBriShip_Outline_9";
                    break;
                case ShipProperty.ShipsType.line_ship_Ten:
                    strName = "LineBriShip_Outline_10";
                    break;
                default:
                    strName = "BriShip_Outline_5";
                    break;
            }
            return strName;
        }
        public void ChangeGrowDirection(bool growDir ) {
            if(growDir != m_growDirection) {
                m_growDirection = growDir;
                ContructBridge( m_growDirection );
            }
        }
        public void ContructBridge(bool growDir) {
            if (VirtualRehearseDic.Count < 3)
                return;
            float growSing = 1.0f;
            Transform briTran = TerrainsMove.Instance.GetBottomRightBridgeTransform();
           
            int index = 0;
            float preShipLength = 0.0f;
            float shipsLength = 0.0f;
            if (!growDir) {
                growSing = -1;
                preShipLength = TransferOfAxes.Instance.GetRiverWidth();
            }
            foreach (var item in VirtualRehearseDic) {
                if (item.Value.virtualObj == null)
                    continue;
                shipsLength = item.Value.length;

                Vector3 shipPos = briTran.TransformPoint(new Vector3((preShipLength + shipsLength * 0.5f * growSing), 0.0f, 0.0f));

                int indexType = GameFunc.Instance.m_ShipTypes == ShipTypes.StraddleType ? 0 : 5;
                shipPos.y = 7.0f;
                if (indexType > 0)
                    item.Value.virtualObj.transform.SetPositionAndRotation(shipPos, briTran.rotation * Quaternion.AngleAxis(90.0f, Vector3.up));
                else
                    item.Value.virtualObj.transform.SetPositionAndRotation(shipPos, briTran.rotation);
                preShipLength += item.Value.length * growSing;
                index++;
                if (index >= m_BestShipOrch.x + m_BestShipOrch.y)
                    return;
            }
            //contruct bridge

        }

        public string GetVirtualNameByID( uint index ) {
            if (VirtualRehearseDic.ContainsKey( (index) )) {
                FsmStateDataBase vd;
                VirtualRehearseDic.TryGetValue( (index), out vd );
                return vd.virtualObj.name;
            }
            return string.Empty;
        }

        public void VirtualShow( uint index, bool visiable ) {

            if (VirtualRehearseDic.ContainsKey( (index) )) {
                FsmStateDataBase vd;
                VirtualRehearseDic.TryGetValue( (index), out vd );
                vd.virtualObj.GetComponentInChildren<MeshRenderer>().enabled = visiable;
            }
        }

        public void ShowAll() {
            foreach (var item in VirtualRehearseDic) {
                item.Value.virtualObj.GetComponentInChildren<MeshRenderer>().enabled = true;
                GameEntry.Instance.FsmManager.GetFsm( item.Value.virtualObj.name ).ChangeState<VStartJumpGpsFirstPositionState>( item.Value );
            }
        }

        public void HideAll() {
            foreach (var item in VirtualRehearseDic) {
                item.Value.virtualObj.GetComponentInChildren<MeshRenderer>().enabled = false;
            }
        }

        // Update is called once per frame
        public void Update() {
            float riverWidth = TransferOfAxes.Instance.GetRiverWidth();
            if (riverWidth < 100.0f)
                return;
            AutoDesiginBridge( riverWidth );
        }

        public void DestoryAll() {
            foreach (var item in VirtualRehearseDic) {
                GameObject.DestroyImmediate( item.Value.virtualObj );
            }
            VirtualRehearseDic.Clear();
        }

        public IFsmState GetFsmStateByShipID( uint shipID ) {
            uint index = ShipsDictionary.Instance.HashCodeConvert( shipID );
            if (VirtualRehearseDic.Count <= index || VirtualRehearseDic.ContainsKey( index ) == false ||
                VirtualRehearseDic[index].virtualObj == null)
                return null;
            string virtualName = VirtualRehearseDic[index].virtualObj.name;
            var fsm = GameEntry.Instance.FsmManager.GetFsm( virtualName );
            if (fsm == null)
                return null; 

            return fsm.CurrentState;
        }


        public IFsmState GetFsmHalfWayStateByShipID( uint shipID ) {

            IEntity entity = GameEntry.Instance.EntityManager.Get( shipID );
            if (entity == null)
                return null;

            var fsm = GameEntry.Instance.FsmManager.GetFsm( entity.Get().name );
            if (fsm == null)
                return null;

            return fsm.CurrentState;
        }

        public string GetFsmName( uint id ) {
            uint index = ShipsDictionary.Instance.HashCodeConvert( id );
            if (VirtualRehearseDic.ContainsKey( index )) {
                return VirtualRehearseDic[index].virtualObj.name;
            }
            return string.Empty;
        }

        public Vector3 GetVirtualShipPosition( uint shipId ) {
            uint index = ShipsDictionary.Instance.HashCodeConvert( shipId );
            var obj = GetDataBaseByIndex( index );
            return obj.virtualObj.transform.position;
        }

        public FsmStateDataBase GetDataBaseByIndex( uint id ) {
            if (VirtualRehearseDic.ContainsKey( id )) {
                FsmStateDataBase fdb;
                VirtualRehearseDic.TryGetValue( id, out fdb );
                return fdb;
            }
            return null;
        }

        public FsmStateDataBase GetDataBaseByShipID( uint shipID ) {
            uint index = ShipsDictionary.Instance.HashCodeConvert( shipID );
            if (VirtualRehearseDic.ContainsKey( index )) {
                FsmStateDataBase fdb;
                VirtualRehearseDic.TryGetValue( index, out fdb );
                return fdb;
            }
            return null;
        }

        public void SetDataBaseByShipID(uint shipID, FsmStateDataBase fsdb)
        {
            uint index = ShipsDictionary.Instance.HashCodeConvert(shipID);
            if (VirtualRehearseDic.ContainsKey(index))
            {
  
                VirtualRehearseDic[index] = fsdb;
            }
        }

        public int  GetVirtualShipCount()
        {
            return VirtualRehearseDic.Count;
        }
        private float GetLength( int type ) {
            switch (type) {
                case 0: {
                        return four_type;
                    }
                case 1: {
                        return five_type;
                    }
                case 2: {
                        return eight_type;
                    }
                case 3: {
                        return nine_type;
                    }
                case 4: {
                        return ten_type;
                    }
            }
            return 0.0f;
        }
    }
}